﻿using System.Collections.Generic;
using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace Chimp.Core
{
    public class ChimpDraw
    {
        public static Vector4 Color = new Vector4(1.0f, 1.0f, 1.0f, 0.85f);
        public static Vector4 TextColor = new Vector4(1, 1, 1, 1);
        public static Vector3 Rotation = new Vector3(0, 0, 0);
        public static Vector3 UVScale = new Vector3(1.0f, 1.0f, 1.0f);

        public static Dictionary<string, ChimpText.ChimpTextCache> TextCache =
            new Dictionary<string, ChimpText.ChimpTextCache>();

        public static ChimpBlend BlendMode = ChimpBlend.Alpha;
        private static ChimpEffect XQuadLit;
        private static ChimpEffect XFrameDistort;
        private static ChimpEffect XShapeBlit;
        private static ChimpEffect XShapeComposite;

        public static void InitChimpDraw()
        {
            XQuadLit = new ChimpEffect("", "Res/Shader/QuadLit.glsl");
            XFrameDistort = new ChimpEffect("", "Res/Shader/FrameDistort.glsl");
            XShapeBlit = new ChimpEffect(null, "Res/Shader/ShapeBlit.glsl");
            XShapeComposite = new ChimpEffect(null, "Res/Shader/ShapeComposite.glsl");
        }

        public static Vector4 Col(float r, float g, float b, float a)
        {
            return new Vector4(r, g, b, a);
        }

        public static Vector4 Col(float r, float g, float b)
        {
            return Col(r, g, b, Color.W);
        }

        public static Vector4 Col1(float r, float g, float b)
        {
            return Col(r, g, b, 1.0f);
        }

        public static Vector4 SetCol(float r, float g, float b, float a)
        {
            Color = Col(r, g, b, a);
            return Color;
        }

        public static Vector4 SetCol(float r, float g, float b)
        {
            Color = Col(r, g, b);
            return Color;
        }

        public static Vector4 SetCol1(float r, float g, float b)
        {
            Color = Col1(r, g, b);
            return Color;
        }

        public static void Begin()
        {
            Rotation = Vector3.Zero;
        }

        public static void End()
        {
        }

        public static void Rect(Vector4 pos, float a, float s, Vector4 col)
        {
            Image(pos, a, s, col, null, false);
        }

        public static void ImageDistort(Vector4 pos, float a, float s, Vector4 col, ChimpTexture2D src,
                                        ChimpTexture2D img, ChimpTexture2D norm, float distort)
        {
            XFrameDistort.Use();
            XFrameDistort.SetInt("SourceMap", 0);
            XFrameDistort.SetInt("FrameMap", 1);
            XFrameDistort.SetInt("DistortMap", 2);
            XFrameDistort.SetVec4("FrameCol", col);
            XFrameDistort.SetFloat("DistortStrength", distort);

            img.Bind(1);
            norm.Bind(2);

            //Image(pos, a, s, col, src,false);
            BasicImage(ref pos, ref a, ref s, ref col, src, false);

            norm.Unbind(2);
            img.Unbind(1);

            XFrameDistort.Fin();
        }

        public static void Image(Vector4 pos, float a, float s, Vector4 col, ChimpTexture2D diffMap,
                                 ChimpTexture2D normMap, ChimpTexture2D specMap, ChimpLight l)
        {
            XQuadLit.Use();
            XQuadLit.SetVec3("LightCol", l.Color);
            XQuadLit.SetVec3("LightSpec", l.Specular);
            XQuadLit.SetFloat("LightShine", l.Shine);
            XQuadLit.SetVec4("QuadCol", col);
            XQuadLit.SetVec3("LightPos", new Vector3(l.Pos.X/ChimpApp.W, l.Pos.Y/ChimpApp.H, 0.2f));
            XQuadLit.SetInt("DiffMap", 0);
            XQuadLit.SetInt("NormMap", 1);
            XQuadLit.SetInt("SpecMap", 2);
            XQuadLit.SetInt("BasicMode", 0);
            normMap.Bind(1);
            specMap.Bind(2);

            Image(pos, a, s, col, diffMap, false);

            specMap.Unbind(2);
            normMap.Unbind(1);

            XQuadLit.Fin();
        }

        public static void ShapeBlit(Vector4 pos, float a, float s, ChimpTexture2D shape, bool flipuv)
        {
            var col = new Vector4(1, 1, 1, 1);
            XShapeBlit.Use();
            XShapeBlit.SetInt("SourceMap", 0);
            BasicImage(ref pos, ref a, ref s, ref col, shape, flipuv);
            XShapeBlit.Fin();
        }

        public static void ShapeComposite(Vector4 pos, ChimpTexture2D src, ChimpTexture2D shape, bool flipuv)
        {
            var col = new Vector4(1, 1, 1, 1);
            XShapeComposite.Use();
            XShapeComposite.SetInt("SourceMap", 0);
            XShapeComposite.SetInt("KeyMap", 1);
            float a = 0;
            float s = 1.0f;
            shape.Bind(1);
            BasicImage(ref pos, ref a, ref s, ref col, src, flipuv);
            shape.Unbind(1);
            XShapeComposite.Fin();
        }

        public static void Image(Vector4 pos, float a, float s, Vector4 col, ChimpTexture2D tex, bool flipuv)
        {
            XQuadLit.Use();

            XQuadLit.SetVec4("QuadCol", col);

            XQuadLit.SetInt("DiffMap", 0);
            XQuadLit.SetInt("BasicMode", 1);
            BasicImage(ref pos, ref a, ref s, ref col, tex, flipuv);

            XQuadLit.Fin();
        }

        public static void BasicImage(ref Vector4 pos, ref float a, ref float s, ref Vector4 col, ChimpTexture2D tex,
                                      bool flipuv)
        {
            float fv = flipuv ? 0.0f : 1.0f;

            Bind();

            GL.Color4(col);

            if (tex != null)
            {
                tex.Bind(0);
            }

            Vector2[] v = ChimpMath.TransformRect(ref pos, ref a, ref s);

            GL.Begin(BeginMode.Quads);

            GL.TexCoord2(0, fv);
            if (ChimpTexture2D.UnitBound[1])
            {
                GL.MultiTexCoord2(TextureUnit.Texture1, v[0].X/ChimpApp.W, v[0].Y/ChimpApp.H);
            }
            GL.Vertex2(v[0]);


            GL.TexCoord2(1, fv);
            if (ChimpTexture2D.UnitBound[1])
            {
                GL.MultiTexCoord2(TextureUnit.Texture1, v[1].X/ChimpApp.W, v[1].Y/ChimpApp.H);
            }
            GL.Vertex2(v[1]);

            GL.TexCoord2(1, 1.0f - fv);
            if (ChimpTexture2D.UnitBound[1])
            {
                GL.MultiTexCoord2(TextureUnit.Texture1, v[2].X/ChimpApp.W, v[2].Y/ChimpApp.H);
            }
            GL.Vertex2(v[2]);

            GL.TexCoord2(0, 1.0f - fv);
            if (ChimpTexture2D.UnitBound[1])
            {
                GL.MultiTexCoord2(TextureUnit.Texture1, v[3].X/ChimpApp.W, v[2].Y/ChimpApp.H);
            }
            GL.Vertex2(v[3]);

            GL.End();

            if (tex != null)
            {
                tex.Unbind(0);
            }
            Unbind();
        }

        public static void Rect(Vector4 pos, Vector4 col)
        {
            //var a = 0.0f;
            //float s = 1.0f;
            // BasicImage(ref pos,ref a,ref s,ref col, null,true);
            Bind();
            GL.Color4(col);
            GL.Begin(BeginMode.Quads);
            GL.Vertex2(pos.X, pos.Y);
            GL.Vertex2(pos.X + pos.Z, pos.Y);
            GL.Vertex2(pos.X + pos.Z, pos.Y + pos.W);
            GL.Vertex2(pos.X, pos.Y + pos.W);
            GL.End();
            Unbind();
        }

        public static Vector2 TextAlign(string txt)
        {
            ChimpText.ChimpTextCache tx = CheckText(txt);

            return new Vector2(-tx.Width/2, -tx.Height/2);
        }

        public static void Text(Vector2 pos, string txt)
        {
            ChimpText.ChimpTextCache tx = CheckText(txt);

            ChimpText.DrawText(tx, (int) pos.X, (int) pos.Y,
                               System.Drawing.Color.FromArgb((int) (TextColor.W*255.0f), (int) (TextColor.X*255.0f),
                                                             (int) (TextColor.Y*255.0f), (int) (TextColor.Z*255.0f)));
        }

        public static ChimpText.ChimpTextCache CheckText(string txt)
        {
            ChimpText.ChimpTextCache tx = null;
            if (txt == null)
            {
                txt = "-";
            }
            string key = txt.Replace(" ", "~");
            if (TextCache.ContainsKey(key))
            {
                tx = TextCache[key];
            }
            else
            {
                tx = ChimpText.CreateText(txt);
                TextCache.Add(key, tx);
            }
            return tx;
        }


        private static void Bind()
        {
            switch (BlendMode)
            {
                case ChimpBlend.Lighten:
                    GL.Enable(EnableCap.Blend);
                    GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.One);
                    GL.Disable(EnableCap.AlphaTest);
                    break;
                case ChimpBlend.Alpha:

                    GL.Enable(EnableCap.Blend);
                    GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
                    GL.Disable(EnableCap.AlphaTest);

                    break;
                case ChimpBlend.Mod:
                    GL.Enable(EnableCap.Blend);
                    GL.BlendFunc(BlendingFactorSrc.DstColor,BlendingFactorDest.SrcColor);
                    break;
            }
        }

        private static void Unbind()
        {
        }


        public static void Image(Vector4 pos, ChimpTexture2D tex, Vector4 Color)
        {
            //Vector2[] pp = ProjectFrame(pos, Rotation, 0.0f);


            Bind();

            GL.Color4(Color);

            if (tex != null)
            {
                tex.Bind(0);
            }
            else
            {
                GL.Disable(EnableCap.Texture2D);
            }

            GL.Begin(BeginMode.Quads);

            GL.TexCoord2(0.0f, 1.0f);
            GL.Vertex2(pos.X, pos.Y);

            GL.TexCoord2(1.0f*UVScale.X, 1.0f);
            GL.Vertex2(pos.X + pos.Z, pos.Y);


            GL.TexCoord2(1.0f*UVScale.X, 0.0f*UVScale.Y);
            GL.Vertex2(pos.X + pos.Z, pos.Y + pos.W);


            GL.TexCoord2(0.0f, 0.0f*UVScale.Y);
            GL.Vertex2(pos.X, pos.Y + pos.W);


            GL.End();

            if (tex != null)
            {
                tex.Unbind(0);
            }

            Unbind();
        }
    }
}